﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace ShanghaiMetroAPP.Helper
{
    /// <summary>
    /// 二维向量的辅助类，绘图基础。
    /// 当绘图时，屏幕中心点为(0,0),向左的单位向量为(-1,0),向下的单位向量为(1,0).
    /// 已重载多种运算符
    /// 这个结构体既可以表示二维向量，也可以表示坐标点，还可以表示Size(尺寸)和一个顶点在(0,0)的矩形。
    /// </summary>
    public struct Vector2
    {
        public double x;
        public double y;
        #region Constructed Method
        public Vector2(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public Vector2(float x, float y)
        {
            this.x = x;
            this.y = y;
        }
        public Vector2(double x, double y)
        {
            this.x = x;
            this.y = y;
        }
        public Vector2(Point p)
        {
            this.x = p.X;
            this.y = p.Y;
        }
        public Vector2(Size size)
        {
            this.x = size.Width;
            this.y = size.Height;
        }
        #endregion

        #region Operator[运算符重载]
        /// <summary>
        /// 已重载，向量相加
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static Vector2 operator +(Vector2 a, Vector2 b)
        {
            return new Vector2()
            {
                x = a.x + b.x,
                y = a.y + b.y
            };
        }
        /// <summary>
        /// 已重载，向量相减，指向被减向量
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Vector2 operator -(Vector2 a, Vector2 b)
        {
            return new Vector2()
            {
                x = a.x - b.x,
                y = a.y - b.y
            };
        }
        /// <summary>
        /// 等量放大，将向量a的x,y分量分别乘b。
        /// 例如使用normal获取一个向量指向的方向并乘2，则会得到长度为2，方向不变的向量。。
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Vector2 operator *(Vector2 a, int b)
        {
            return new Vector2()
            {
                x = a.x * b,
                y = a.y * b
            };
        }
        /// <summary>
        /// 等量放大/缩小，将向量a的x,y分量分别乘b。
        /// 例如使用normal获取一个向量指向的方向并乘2，则会得到长度为2，方向不变的向量。。
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Vector2 operator *(Vector2 a, float b)
        {
            return new Vector2()
            {
                x = a.x * b,
                y = a.y * b
            };
        }
        /// <summary>
        /// 等量放大/缩小，将向量a的x,y分量分别乘b。
        /// 例如使用normal获取一个向量指向的方向并乘2，则会得到长度为2，方向不变的向量。。
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Vector2 operator *(Vector2 a, double b)
        {
            return new Vector2()
            {
                x = a.x * b,
                y = a.y * b
            };
        }
        #endregion

        #region Static Propery
        private static readonly Vector2 _zero = new Vector2(0, 0);
        private static readonly Vector2 _left = new Vector2(-1, 0);
        private static readonly Vector2 _right = new Vector2(1, 0);
        private static readonly Vector2 _up = new Vector2(0, 1);
        private static readonly Vector2 _down = new Vector2(0, -1);
        /// <summary>
        /// 返回一个零向量,零向量不表示任何方向，长度为0.
        /// </summary>
        public static Vector2 zero => _zero;
        /// <summary>
        /// 返回一个指向屏幕正左方的单位向量。(单位向量:长度为1，方向任意)
        /// </summary>
        public static Vector2 left => _left;
        /// <summary>
        /// 返回一个指向屏幕正右方的单位向量。(单位向量:长度为1，方向任意)
        /// </summary>
        public static Vector2 right => _right;
        /// <summary>
        /// 返回一个指向屏幕正上方的单位向量。(单位向量:长度为1，方向任意)
        /// </summary>
        public static Vector2 up => _up;
        /// <summary>
        /// 返回一个指向屏幕正下方的单位向量。(单位向量:长度为1，方向任意)
        /// </summary>
        public static Vector2 down => _down;

        #endregion

        #region Static Methods
        /// <summary>
        /// 获取两向量形成的锐角夹角，单位:角度，值域:(0~90]
        /// TODO:Norman Lee，完善此函数
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static float Angle(Vector2 a, Vector2 b)
        {

            return 0f;
        }
        /// <summary>
        /// 极坐标位移，表示将向量a向angle角度移动length距离;
        /// angle - 单位:角度
        /// length - 单位:px
        /// <para>[不推荐使用],使用向量的加法可以更好地解决问题</para>
        /// </summary>
        /// <param name="a"></param>
        /// <param name="angle"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static Vector2 Offset(Vector2 a,double angle,double length)
        {
            var result = new Vector2();
            result.x = a.x + a.x / Math.Cos(angle * Math.PI / 180) * length;
            result.y = a.y + a.y / Math.Sin(angle * Math.PI / 180) * length;
            return result; 
        }
 
        /// <summary>
        /// 获取两向量连线的线段的中点坐标。
        /// TODO:Norman Lee，检查此函数是否有错误
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Vector2 MidPoint(Vector2 a, Vector2 b)
        {
            var result = new Vector2();
            result.x = (a.x + b.x) / 2.0;
            result.y = (b.y + b.y) / 2.0;
            return result;
        }
        /// <summary>
        /// 已重载
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("Vector2:{0},{1}", x, y);
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// 取向量模长,该值一定大于等于0
        /// </summary>
        public double length
        {
            get
            {
                // √(x^2 + y^2)
                return Math.Sqrt(x * x + y * y);
            }
        }
        /// <summary>
        /// 令向量方向不变，并取单位向量
        /// </summary>
        public Vector2 normalized
        {
            get
            {
                var length = this.length;
                var param = 1.0 / length;
                return this * param;
            }
        }
        public Size size
        {
            get
            {
                return new Size(Math.Abs(x), Math.Abs(y));
            }
        }
        public Point point
        {
            get
            {
                return new Point(x, y);
            }
        }
        #endregion

    }
}
